rbtree: Move to an approach where we don't move contents
authorBenjamin Otte <otte@redhat.com>
Mon, 21 Nov 2011 15:07:52 +0000 (16:07 +0100)
committerBenjamin Otte <otte@redhat.com>
Mon, 21 Nov 2011 21:33:45 +0000 (22:33 +0100)
So instead of copying the children and height to the new node, we keep
the old node and copy all the old stuff to it.

This is necessary so the accessibility code can use the node as a key in
the hash table or store the node as a reference to the row instead of
GtkTreeRowReference. And because it already does that (oops), this fixes
a bunch of segfaults with a11y enabled.

gtk/gtkrbtree.c

index b8f912222d452e2fcfe69b46c7d1b984813e2812..d327268ff26869f1f866ca066eac1bcd77d8ac33 100644 (file)
@@ -1199,37 +1199,54 @@ _gtk_rbtree_remove_node (GtkRBTree *tree,
 
   if (y != node)
     {
-      gint count_diff, height_diff;
+      gint node_height, node_total_count;
 
-      /* We want to see how different our height is from the previous node.
-       * To do this, we compare our current height with our supposed height.
+      /* We want to see how much we remove from the aggregate values.
+       * This is all the children we remove plus the node's values.
        */
-      height_diff = y_height 
-                    - GTK_RBNODE_GET_HEIGHT (node)
-                    - (node->children ? node->children->root->offset : 0);
-      count_diff = y->total_count - node->total_count;
-
-      /* Copy the node over */
-      if (GTK_RBNODE_GET_COLOR (node) == GTK_RBNODE_BLACK)
-       node->flags = ((y->flags & (GTK_RBNODE_NON_COLORS)) | GTK_RBNODE_BLACK);
-      else
-       node->flags = ((y->flags & (GTK_RBNODE_NON_COLORS)) | GTK_RBNODE_RED);
-      if (y->children)
-       {
-         node->children = y->children;
-         node->children->parent_node = node;
-       }
+      node_height = GTK_RBNODE_GET_HEIGHT (node)
+                    + (node->children ? node->children->root->offset : 0);
+      node_total_count = 1
+                         + (node->children ? node->children->root->total_count : 0);
+
+      /* Move the node over */
+      if (GTK_RBNODE_GET_COLOR (node) != GTK_RBNODE_GET_COLOR (y))
+        {
+         node->flags ^= (GTK_RBNODE_BLACK | GTK_RBNODE_RED);
+         y->flags ^= (GTK_RBNODE_BLACK | GTK_RBNODE_RED);
+        }
+
+      y->left = node->left;
+      if (y->left != tree->nil)
+        y->left->parent = y;
+      y->right = node->right;
+      if (y->right != tree->nil)
+        y->right->parent = y;
+      y->parent = node->parent;
+      if (y->parent != tree->nil)
+        {
+          if (y->parent->left == node)
+            y->parent->left = y;
+          else
+            y->parent->right = y;
+        }
       else
-       {
-         node->children = NULL;
-       }
+        {
+          tree->root = y;
+        }
+      y->count = node->count;
+      y->total_count = node->total_count;
+      y->offset = node->offset;
 
-      gtk_rbnode_adjust (tree, node, 0, count_diff, height_diff);
+      gtk_rbnode_adjust (tree, y, 
+                         0,
+                         y_total_count - node_total_count,
+                         y_height - node_height);
     }
 
-  if (GTK_RBNODE_GET_COLOR (y) == GTK_RBNODE_BLACK)
+  if (GTK_RBNODE_GET_COLOR (node) == GTK_RBNODE_BLACK)
     _gtk_rbtree_remove_node_fixup (tree, x);
-  _gtk_rbnode_free (y);
+  _gtk_rbnode_free (node);
 
 #ifdef G_ENABLE_DEBUG  
   if (gtk_get_debug_flags () & GTK_DEBUG_TREE)